home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume11 / ppm-utils / part01 next >
Encoding:
Text File  |  1990-03-25  |  25.5 KB  |  992 lines

  1. Newsgroups: comp.sources.misc
  2. From: bturner@hpcvxbt.cv.hp.com (Bill Turner)
  3. subject: v11i084: Four new PPM utilities
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 11, Issue 84
  7. Submitted-by: bturner@hpcvxbt.cv.hp.com (Bill Turner)
  8. Archive-name: ppm-utils/part01
  9.  
  10. After getting the PBMPLUS stuff, I found there were some things I'd still like
  11. to be able to do -- in particular, the pbm programs seemed weak at combining
  12. images together.  Part of that is because I didn't read the documentation
  13. (yes, RTFM), but I didn't see a good way of "concatenating" images together.
  14. Also, since I enjoy tinkering with code, I wanted to see how the PBM code
  15. worked.  Anyway, from this was born the following four programs:  ppmfill,
  16. ppmborder, ppmmerge, and ppmoverlay.
  17.  
  18. ppmfill is basically a subset of pnmtile (since it only works with ppm's).
  19. ppmborder writes a border around a ppmfile (could be done with pnmtile and
  20.    pnmpaste, but I like the cleanliness of a single program).
  21. ppmmerge concatenates a number of ppm files together, either side by side or
  22.    stacked vertically.
  23. ppmoverlay is similar to pnmpaste, with a different interface (specify border
  24.     size and corner [i.e., top left] rather than (x, y) offset).
  25.  
  26. Even if nobody finds these useful, I wrote 'em, so I'm submitting 'em!
  27.  
  28. --Bill Turner (bturner@hp-pcd.cv.hp.com)
  29. Hewlett-Packard Information Technology Operation
  30.  
  31. ---------------------------------cut here-------------------------------------
  32. #! /bin/sh
  33. #
  34. # This is a shell archive.  Remove anything before this line,
  35. # then unpack it by saving it in a file and typing "sh file".
  36. #
  37. # Wrapped by Bill Turner <bturner@hp-pcd.cv.hp.com> on Mon Mar 19 14:11:26 1990
  38. #
  39. # This archive contains:
  40. #    ppmfill.1    ppmborder.1    ppmmerge.1    ppmoverlay.1    
  41. #    ppmfill.c    ppmborder.c    ppmmerge.c    ppmoverlay.c    
  42. #
  43.  
  44. LANG=""; export LANG
  45. PATH=/bin:/usr/bin:$PATH; export PATH
  46.  
  47. echo x - ppmfill.1
  48. cat >ppmfill.1 <<'@EOF'
  49. .TH ppmfill 1 "19 March 1990"
  50. .SH NAME
  51. ppmfill - fill an area with a tiled ppm
  52. .SH SYNOPSIS
  53. pbmfill <width> <height> [ppmfile]
  54. .SH DESCRIPTION
  55. Produces a portable pixmap of the specified width and height,
  56. with a pattern in it.  The specified ppmfile (or stdin, if no
  57. file is specified) is tiled to create a new ppmfile of the specified
  58. size.
  59. .SH "SEE ALSO"
  60. pnmtile(1), ppmborder(1), ppm(5)
  61.  
  62. This was written without reading the ppm documentation, and is functionally a
  63. subset of pnmtile (since ppmfill only handles ppm's).  But since I spent the
  64. time doing it, I'm damn well going to send it out!
  65. .SH AUTHOR
  66. Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
  67. from the original PBM source, below is the original copyright notice.
  68.  
  69. Copyright (C) 1989 by Jef Poskanzer.
  70.  
  71. Permission to use, copy, modify, and distribute this software and its
  72. documentation for any purpose and without fee is hereby granted, provided
  73. that the above copyright notice appear in all copies and that both that
  74. copyright notice and this permission notice appear in supporting
  75. documentation.  This software is provided "as is" without express or
  76. implied warranty.
  77. @EOF
  78.  
  79. chmod 644 ppmfill.1
  80.  
  81. echo x - ppmborder.1
  82. cat >ppmborder.1 <<'@EOF'
  83. .TH ppmborder 1 "19 March 1990"
  84. .SH NAME
  85. ppmborder - add a border around a ppm file
  86. .SH SYNOPSIS
  87. ppmborder <width> <borderfile> [ppmfile]
  88. .SH DESCRIPTION
  89. Uses a tile of
  90. .I borderfile
  91. as a border around a ppmfile.  The ppmfile produced is larger than the
  92. original.
  93. .I width
  94. specifies the width of the border to produce.
  95. .SH "SEE ALSO"
  96. pnmtile(1), ppmfill(1), ppm(5)
  97. .SH AUTHOR
  98. Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
  99. from the original PBM source, below is the original copyright notice.
  100.  
  101. Copyright (C) 1989 by Jef Poskanzer.
  102.  
  103. Permission to use, copy, modify, and distribute this software and its
  104. documentation for any purpose and without fee is hereby granted, provided
  105. that the above copyright notice appear in all copies and that both that
  106. copyright notice and this permission notice appear in supporting
  107. documentation.  This software is provided "as is" without express or
  108. implied warranty.
  109. @EOF
  110.  
  111. chmod 644 ppmborder.1
  112.  
  113. echo x - ppmmerge.1
  114. cat >ppmmerge.1 <<'@EOF'
  115. .TH ppmmerge 1 "19 March 1990"
  116. .SH NAME
  117. ppmmerge - merge ppmfiles together
  118. .SH SYNOPSIS
  119. ppmmerge [-v | -h] ppmfile...
  120. .SH DESCRIPTION
  121. Concatenates the ppmfiles either side-by-side (
  122. .I -h
  123. , the default) or one on
  124. top of the other (
  125. .I -v
  126. ).  Any number of ppm files may be specified, but it doesn't make much sense
  127. to have less than two.
  128. .PP
  129. This is useful for producing a "collection" image, where a number of images
  130. are merged into a single file.
  131. .SH "SEE ALSO"
  132. ppmoverlay(1), ppm(5)
  133. .SH AUTHOR
  134. Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
  135. from the original PBM source, below is the original copyright notice.
  136.  
  137. Copyright (C) 1989 by Jef Poskanzer.
  138.  
  139. Permission to use, copy, modify, and distribute this software and its
  140. documentation for any purpose and without fee is hereby granted, provided
  141. that the above copyright notice appear in all copies and that both that
  142. copyright notice and this permission notice appear in supporting
  143. documentation.  This software is provided "as is" without express or
  144. implied warranty.
  145. @EOF
  146.  
  147. chmod 644 ppmmerge.1
  148.  
  149. echo x - ppmoverlay.1
  150. cat >ppmoverlay.1 <<'@EOF'
  151. .TH ppmoverlay 1 "19 March 1990"
  152. .SH NAME
  153. ppmoverlay - overlay one ppm over the top of another
  154. .SH SYNOPSIS
  155. ppmoverlay [-top|-vcenter|-bottom] [-left|-hcenter|-right] [-border #]
  156. ppmfile [ppmbackground]
  157. .SH DESCRIPTION
  158. Overlays a ppmfile over the specified background (or stdin, if no background
  159. file is specified).  The default is to center the image over the background,
  160. but this may be overridden with the flags.
  161. .IP -top 10
  162. The image is placed along the top border.
  163. .IP -vcenter 10
  164. (Default) The image is centered vertically.
  165. .IP -bottom 10
  166. The image is placed along the bottom border.
  167. .IP -left 10
  168. The image is placed along the left border.
  169. .IP -hcenter 10
  170. (Default) The image is centered horizontally.
  171. .IP -right 10
  172. The image is placed along the right border.
  173. .IP -border 10
  174. Specifies the border width to use (default = 0).
  175. .PP
  176. If the source image is too small to fit on the background with the specified
  177. border width, an error message is generated.
  178. .PP
  179. This is useful for generating "collection" images.
  180. .SH "KNOWN PROBLEMS"
  181. The border width is used for both the vertical and horizontal borders.  There
  182. is no way to specify separate border sizes (although this is an easy
  183. modification to make, and it should be done).
  184. .SH "SEE ALSO"
  185. pnmtile(1), ppmfill(1), ppm(5)
  186. .SH AUTHOR
  187. Bill Turner, Hewlett-Packard Company.  Since the work is heavily leveraged
  188. from the original PBM source, below is the original copyright notice.
  189.  
  190. Copyright (C) 1989 by Jef Poskanzer.
  191.  
  192. Permission to use, copy, modify, and distribute this software and its
  193. documentation for any purpose and without fee is hereby granted, provided
  194. that the above copyright notice appear in all copies and that both that
  195. copyright notice and this permission notice appear in supporting
  196. documentation.  This software is provided "as is" without express or
  197. implied warranty.
  198. @EOF
  199.  
  200. chmod 644 ppmoverlay.1
  201.  
  202. echo x - ppmfill.c
  203. cat >ppmfill.c <<'@EOF'
  204. /* ppmfill - fill a rectangle with a tiling of a ppm file
  205. **
  206. ** Written 3/90 by Bill Turner, heavily leveraged from code by Jef Poskanzer,
  207. ** hence the copyright below.
  208. **
  209. ** Copyright (C) 1989 by Jef Poskanzer.
  210. **
  211. ** Permission to use, copy, modify, and distribute this software and its
  212. ** documentation for any purpose and without fee is hereby granted, provided
  213. ** that the above copyright notice appear in all copies and that both that
  214. ** copyright notice and this permission notice appear in supporting
  215. ** documentation.  This software is provided "as is" without express or
  216. ** implied warranty.
  217. */
  218.  
  219. #include <stdio.h>
  220. #include "ppm.h"
  221.  
  222. main( argc, argv )
  223. int argc;
  224. char *argv[];
  225.     {
  226.     FILE *ifd;
  227.     pixel **pixels, *newpixelrow;
  228.     register pixel *sP, *dP;
  229.     int argn, rows, cols, newrows, newcols, row, col, irow, icol;
  230.     pixval maxval;
  231.     char *usage = "width height [ppmfile]";
  232.  
  233.     pm_progname = argv[0];
  234.  
  235.     argn = 1;
  236.  
  237.     if ( argc < 3 )
  238.     pm_usage( usage );
  239.  
  240.     if ( sscanf( argv[argn++], "%d", &newcols) != 1 )
  241.     pm_usage( usage );
  242.  
  243.     if ( sscanf( argv[argn++], "%d", &newrows) != 1)
  244.     pm_usage( usage );
  245.  
  246.     if ( argn != argc )
  247.     {
  248.     ifd = pm_openr( argv[argn] );
  249.     argn++;
  250.     }
  251.     else
  252.     ifd = stdin;
  253.  
  254.     if ( argn != argc )
  255.     pm_usage( usage );
  256.  
  257.     ppm_pbmmaxval = 255;    /* use larger value for better results */
  258.     pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
  259.  
  260.     pm_close( ifd );
  261.  
  262.     ppm_writeppminit( stdout, newcols, newrows, maxval );
  263.     newpixelrow = ppm_allocrow( newcols );
  264.  
  265.     for ( row = 0, irow = 0; row < newrows; row++ )
  266.     {
  267.  
  268. /* Each destination row consinsts of a repatition of input rows.  The source
  269.  * pointer is reset to the starting point every cols pixels.  This could also
  270.  * have been done using moduls, i.e. *dP++ = pixels[irow][col % cols], or
  271.  * ultimately *dP++ = pixels[row % rows][col % cols].  I'm not exactly sure
  272.  * which produces the most efficient code.
  273.  */
  274.  
  275.     for ( col = 0, icol = 0, sP = pixels[irow], dP = newpixelrow;
  276.           col < newcols;
  277.           col++ )
  278.         {
  279.         *dP++ = *sP++;
  280.         if (++icol >= cols)        /* End of input, reset to start of row */
  281.         {
  282.         icol = 0;
  283.         sP = pixels[irow];
  284.         }
  285.         }
  286.  
  287.     ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
  288.  
  289. /* Similar with columns, need to repeat ever "rows" row.  */
  290.  
  291.     if (++irow >= rows)
  292.         irow = 0;
  293.     }
  294.  
  295.     exit(0);
  296.     }
  297. @EOF
  298.  
  299. chmod 644 ppmfill.c
  300.  
  301. echo x - ppmborder.c
  302. cat >ppmborder.c <<'@EOF'
  303. /* ppmborder - create a border with a tile of a ppm file.
  304. **
  305. ** Written 3/90 by Bill Turner, heavily leveraged from code by Jef Poskanzer,
  306. ** hence the copyright below.
  307. **
  308. ** Copyright (C) 1989 by Jef Poskanzer.
  309. **
  310. ** Permission to use, copy, modify, and distribute this software and its
  311. ** documentation for any purpose and without fee is hereby granted, provided
  312. ** that the above copyright notice appear in all copies and that both that
  313. ** copyright notice and this permission notice appear in supporting
  314. ** documentation.  This software is provided "as is" without express or
  315. ** implied warranty.
  316. */
  317.  
  318. #include <stdio.h>
  319. #include "ppm.h"
  320.  
  321. main( argc, argv )
  322. int argc;
  323. char *argv[];
  324.     {
  325.     FILE *ifd, *borderfd;
  326.     pixel **pixels, **borderpixels, *newpixelrow;
  327.     register pixel *sP, *dP, *bP;
  328.     int argn, rows, cols, row, col;
  329.     int brows, bcols, brow, bcol, border, newcols;
  330.     pixval maxval;
  331.     char *usage = "width ppmfile [ppmfile]";
  332.  
  333.     pm_progname = argv[0];
  334.  
  335.     argn = 1;
  336.  
  337.     if ( argc < 3 )
  338.     pm_usage( usage );
  339.  
  340.     if ( sscanf( argv[argn++], "%d", &border) != 1 )
  341.     pm_usage( usage );
  342.  
  343.  
  344.     if ( argn != argc )
  345.     {
  346.     borderfd = pm_openr( argv[argn] );
  347.     argn++;
  348.     }
  349.     else
  350.     pm_usage( usage );
  351.  
  352.     if ( argn != argc )
  353.     {
  354.     ifd = pm_openr( argv[argn] );
  355.     argn++;
  356.     }
  357.     else
  358.     ifd = stdin;
  359.  
  360.     if ( argn != argc )
  361.     pm_usage( usage );
  362.  
  363.     ppm_pbmmaxval = 255;    /* use larger value for better results */
  364.     borderpixels = ppm_readppm( borderfd, &brows, &bcols, &maxval);
  365.     pm_close( borderfd );
  366.  
  367.     pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
  368.     pm_close( ifd );
  369.     newcols = cols + border * 2;  /* New width includes left and right border */
  370.  
  371.     ppm_writeppminit( stdout, newcols, rows + border * 2, maxval );
  372.     newpixelrow = ppm_allocrow( newcols );
  373.  
  374. /* For the topborder rows, simply tile from the border ppm. */
  375. /* (See the ppmfill code for a description of the tiling and possible
  376.  * changes.)
  377.  */
  378.  
  379.     for ( row = 0, brow = 0; row < border; row++ )
  380.     {
  381.     for ( col = 0, bcol = 0, dP = newpixelrow, bP = borderpixels[brow];
  382.           col < newcols;
  383.           col++)
  384.         {
  385.         *dP++ = *bP++;
  386.         if ( ++bcol >= bcols )
  387.         {
  388.         bcol = 0;
  389.         bP = borderpixels[brow];
  390.         }
  391.         }
  392.  
  393.     ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
  394.  
  395.     if ( ++brow >= brows )
  396.         brow = 0;
  397.     }
  398.  
  399. /* For the "middle" rows, first copy the left border bits from the tile, then
  400.  * copy the image row, then the right border bits from the tile.
  401.  */
  402.  
  403.     for ( row = 0; row < rows; row++ )
  404.     {
  405.  
  406. /* Left border */
  407.     for ( col = 0, bcol = 0, dP = newpixelrow, bP = borderpixels[brow];
  408.           col < border;
  409.           col++ )
  410.         {
  411.         *dP++ = *bP++;
  412.         if ( ++bcol >= bcols )
  413.         {
  414.         bcol = 0;
  415.         bP = borderpixels[brow];
  416.         }
  417.         }
  418.  
  419. /* Image bits */
  420.     for ( col = 0, sP = pixels[row];
  421.           col < cols;
  422.           col++ )
  423.         {
  424.         *dP++ = *sP++;
  425.         }
  426.  
  427. /* Right border */
  428.     bcol = (cols + border) % bcols;
  429.     for ( col = 0, bP = &borderpixels[brow][bcol];
  430.           col < border;
  431.           col++ )
  432.         {
  433.         *dP++ = *bP++;
  434.         if ( ++bcol >= bcols )
  435.         {
  436.         bcol = 0;
  437.         bP = borderpixels[brow];
  438.         }
  439.         }
  440.  
  441.     ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
  442.     if (++brow >= brows)
  443.         brow = 0;
  444.     }
  445.  
  446. /* As with the top border, so with the bottom border. */
  447.  
  448.     for ( row = 0; row < border; row++ )
  449.     {
  450.     for ( col = 0, bcol = 0, dP = newpixelrow, bP = borderpixels[brow];
  451.           col < cols + border * 2;
  452.           col++)
  453.         {
  454.         *dP++ = *bP++;
  455.         if ( ++bcol >= bcols )
  456.         {
  457.         bcol = 0;
  458.         bP = borderpixels[brow];
  459.         }
  460.         }
  461.  
  462.     ppm_writeppmrow( stdout, newpixelrow, newcols, maxval );
  463.  
  464.     if ( ++brow >= brows )
  465.         brow = 0;
  466.     }
  467.     
  468.     exit(0);
  469.     }
  470. @EOF
  471.  
  472. chmod 644 ppmborder.c
  473.  
  474. echo x - ppmmerge.c
  475. cat >ppmmerge.c <<'@EOF'
  476. /* ppmmerge.c - merge two or more portable pixmaps
  477. **
  478. ** Written 3/90 by Bill Turner, but leveraged heavily from code by Jef
  479. ** Poskanzer (extensive use of the PBM code), so the copyright notice is
  480. ** attached below.
  481. **
  482. ** Copyright (C) 1989 by Jef Poskanzer.
  483. **
  484. ** Permission to use, copy, modify, and distribute this software and its
  485. ** documentation for any purpose and without fee is hereby granted, provided
  486. ** that the above copyright notice appear in all copies and that both that
  487. ** copyright notice and this permission notice appear in supporting
  488. ** documentation.  This software is provided "as is" without express or
  489. ** implied warranty.
  490. */
  491.  
  492. #include <stdio.h>
  493. #include "ppm.h"
  494.  
  495. void WriteStack();
  496. void WriteSide();
  497.  
  498. main( argc, argv )
  499. int argc;
  500. char *argv[];
  501.     {
  502.     FILE *ifd;
  503.     pixel **pixels, *newpixelrow;
  504.     pixel ***pixel_list;
  505.     register pixel *pP, *npP;
  506.     pixel bgpixel, prevpixel, p;
  507.     int argn, rows, cols, newrows, newcols, row, col, new;
  508.     pixval maxval;
  509.     int *cols_list, *rows_list, *pad_list;
  510.     pixval *maxval_list;
  511.     int num_files;
  512.     char *usage = "[-v | -h] ppmfile...";
  513.     int stack = 0;
  514.     int i;
  515.  
  516.     pm_progname = argv[0];
  517.  
  518.     argn = 1;
  519.  
  520. /* Create lists for file data (dynamic allocation, since there can be an
  521.  * indeterminate number of files)
  522.  */
  523.  
  524.     pixel_list = (pixel ***) malloc(sizeof(pixel **));
  525.     rows_list = (int *) malloc(sizeof(int));
  526.     cols_list = (int *) malloc(sizeof(int));
  527.     maxval_list = (pixval *) malloc(sizeof(pixval));
  528.  
  529.     if ( argn == argc )
  530.     pm_usage( usage );
  531.  
  532.     if ( strcmp(argv[argn], "-h") == 0 ) {
  533.     stack = 0;
  534.     argn++;
  535.     }
  536.     else if ( strcmp(argv[argn], "-v") == 0) {
  537.     stack = 1;
  538.     argn++;
  539.     }
  540.  
  541.     if ( argn == argc )
  542.     pm_usage( usage );
  543.  
  544. /* Read all files */
  545.     num_files = 0;
  546.     while ( argn != argc )
  547.     {
  548.     ifd = pm_openr( argv[argn] );
  549.     num_files++;
  550.     argn++;
  551.  
  552.         ppm_pbmmaxval = 255;    /* use larger value for better results */
  553.         pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
  554.  
  555.         pm_close( ifd );
  556.  
  557. /* Copy data to information arrays (realloc to add new record) */
  558.  
  559.     pixel_list = (pixel ***) realloc(pixel_list,
  560.                      sizeof(pixel **) * num_files);
  561.     rows_list = (int *) realloc(rows_list, sizeof(int) * num_files);
  562.     cols_list = (int *) realloc(cols_list, sizeof(int) * num_files);
  563.     maxval_list = (pixval *) realloc(maxval_list,
  564.                      sizeof(pixval) * num_files);
  565.  
  566.     pixel_list[num_files - 1] = pixels;
  567.     rows_list[num_files - 1] = rows;
  568.     cols_list[num_files - 1] = cols;
  569.     maxval_list[num_files - 1] = maxval;
  570.     }
  571.  
  572. /* After reading in all the files, find the new width and height.  If stack
  573.  * is true, then the images are being stacked on top of each other -- width
  574.  * is the maximum of all widths, height is the sum of the heights.  If stack
  575.  * is false, then put images beside each other -- width is the sum of the
  576.  * widths, and height is the sum of the heights.
  577.  */
  578.  
  579.     newcols = newrows = 0;
  580.     for (i = 0; i < num_files; i++)
  581.     {
  582.     if (stack)
  583.         {
  584.         if (newcols < cols_list[i])
  585.         newcols = cols_list[i];
  586.         newrows += rows_list[i];
  587.         }
  588.     else
  589.         {
  590.         if (newrows < rows_list[i])
  591.         newrows = rows_list[i];
  592.         newcols += cols_list[i];
  593.         }
  594.     if (maxval < maxval_list[i])
  595.         maxval = maxval_list[i];
  596.     }
  597.  
  598. /* Call the appropriate Write routine -- WriteStack, or WriteSide -- to write
  599.  * the merged PPM file.
  600.  */
  601.  
  602.     if (stack)
  603.     {
  604.  
  605. /* Find the left-side padding for each file first */
  606.  
  607.     pad_list = (int *) malloc(sizeof(int) * num_files);
  608.     for (i = 0; i < num_files; i++)
  609.         if (cols_list[i] < newcols)
  610.         pad_list[i] = (newcols + 1 - cols_list[i]) / 2;
  611.         else
  612.         pad_list[i] = 0;
  613.  
  614.     WriteStack(pixel_list, cols_list, rows_list, pad_list,
  615.                    newcols, newrows, maxval, num_files);
  616.     }
  617.     else
  618.     {
  619.  
  620. /* Find the top-side padding for each file first */
  621.  
  622.     pad_list = (int *) malloc(sizeof(int) * num_files);
  623.     for (i = 0; i < num_files; i++)
  624.         if (rows_list[i] < newrows)
  625.         pad_list[i] = (newrows + 1 - rows_list[i]) / 2;
  626.         else
  627.         pad_list[i] = 0;
  628.     WriteSide(pixel_list, cols_list, rows_list, pad_list,
  629.                   newcols, newrows, maxval, num_files);
  630.     }
  631.  
  632.     exit(0);
  633.     }
  634.  
  635.  
  636. /* WriteStack writes each image, one on top of each other.  Simply write out
  637.  * each image sequentially, with padding as required to get a consistent
  638.  * width.
  639.  */
  640.  
  641. void WriteStack(pix_list, cols_list, rows_list, pad_list,
  642.         newcols, newrows, maxval, count)
  643. pixel ***pix_list;
  644. int *cols_list;
  645. int *rows_list;
  646. int *pad_list;
  647. int newcols;
  648. int newrows;
  649. pixval maxval;
  650. int count;
  651.     {
  652.     int file, col, row;
  653.     pixel *newrow, *srcP, *destP, bgpixel;
  654.  
  655.     ppm_writeppminit( stdout, newcols, newrows, maxval );
  656.     newrow = ppm_allocrow(newcols);
  657.     
  658.     for (file = 0; file < count; file++)
  659.     {
  660.  
  661. /* Calculate the background pixel to use for filling (if pad is non-zero) */
  662.  
  663.     bgpixel = ppm_backgroundpixel(pix_list[file],
  664.                       cols_list[file],
  665.                       rows_list[file]);
  666.     for (row = 0; row < rows_list[file]; row++)
  667.         {
  668.         destP = newrow;
  669.         srcP = pix_list[file][row];
  670.         for( col = 0; col < pad_list[file]; col++ )        /* Add left pad */
  671.         *destP++ = bgpixel;
  672.  
  673.         for(col = 0; col < cols_list[file]; col++)
  674.         *destP++ = *srcP++;
  675.  
  676.         for(col = cols_list[file]; col < newcols - pad_list[file]; col++)
  677.         *destP++ = bgpixel;                /* Add right pad */
  678.  
  679.         ppm_writeppmrow( stdout, newrow, newcols, maxval );
  680.         }
  681.     }
  682.     }
  683.  
  684.  
  685. /* WriteSide writes the images side-by-side.  This requires appending scan
  686.  * lines from each file together to produce an output scanline.  Also requires
  687.  * adding a blank scanline for top and bottom padding to get a consistent
  688.  * height.
  689.  */
  690.  
  691. void WriteSide(pix_list, cols_list, rows_list, pad_list,
  692.            newcols, newrows, maxval, count)
  693. pixel ***pix_list;
  694. int *cols_list;
  695. int *rows_list;
  696. int *pad_list;
  697. int newcols;
  698. int newrows;
  699. pixval maxval;
  700. int count;
  701.     {
  702.     int file, col, row;
  703.     pixel *newrow, *srcP, *destP, bgpixel;
  704.  
  705.     ppm_writeppminit( stdout, newcols, newrows, maxval );
  706.     newrow = ppm_allocrow(newcols);
  707.  
  708.     for (row = 0; row < newrows; row++)
  709.     {
  710.     destP = newrow;
  711.     for (file = 0; file < count; file++)
  712.         {
  713.  
  714. /* Check to see if we are in the pad region, either top or bottom. */
  715.  
  716.         if ((row < pad_list[file]) ||
  717.         (row >= rows_list[file] + pad_list[file]))
  718.         {
  719.  
  720. /* Fill with the background pixel for a pad. */
  721.  
  722.         bgpixel = ppm_backgroundpixel( pix_list[file],
  723.                            cols_list[file],
  724.                            rows_list[file] );
  725.         for (col = 0; col < cols_list[file]; col++)
  726.             *destP++ = bgpixel;
  727.         }
  728.         else
  729.         {
  730.  
  731. /* Copy the appropriate source row (absolute row number minus the number of
  732.  * padding rows required).
  733.  */
  734.  
  735.         srcP = pix_list[file][row - pad_list[file]];
  736.         for (col = 0; col < cols_list[file]; col++)
  737.             *destP++ = *srcP++;
  738.         }
  739.         }
  740.  
  741.     ppm_writeppmrow( stdout, newrow, newcols, maxval );
  742.     }
  743.     }
  744. @EOF
  745.  
  746. chmod 644 ppmmerge.c
  747.  
  748. echo x - ppmoverlay.c
  749. cat >ppmoverlay.c <<'@EOF'
  750. /* ppmoverlay - overlay one ppm file over the top of another.
  751. **
  752. ** Written 3/90 by Bill Turner, heavily leveraged from code by Jef Poskanzer,
  753. ** hence the copyright below.
  754. **
  755. ** Copyright (C) 1989 by Jef Poskanzer.
  756. **
  757. ** Permission to use, copy, modify, and distribute this software and its
  758. ** documentation for any purpose and without fee is hereby granted, provided
  759. ** that the above copyright notice appear in all copies and that both that
  760. ** copyright notice and this permission notice appear in supporting
  761. ** documentation.  This software is provided "as is" without express or
  762. ** implied warranty.
  763. */
  764.  
  765. #include <stdio.h>
  766. #include "ppm.h"
  767.  
  768. #define UNSPECIFIED 0
  769. #define LEFT 1
  770. #define CENTER 2
  771. #define RIGHT 3
  772.  
  773. #define TOP 1
  774. #define BOTTOM 3
  775.  
  776. main( argc, argv )
  777. int argc;
  778. char *argv[];
  779.     {
  780.     FILE *ifd, *bfd;
  781.     pixel **pixels, **backpixels, *newpixelrow;
  782.     register pixel *sP, *bP, *dP;
  783.     int argn, rows, cols, backrows, backcols, row, col;
  784.     int topborder, bottomborder, leftborder, rightborder, minborder;
  785.     int brow, bcol;
  786.     int valign, halign;
  787.     pixval maxval, backmax;
  788.     char *usage = "[-top | -vcenter | -bottom] [-left | -hcenter |
  789. -right] [-border #] ppmfile [ppmbackground]";
  790.  
  791.     pm_progname = argv[0];
  792.  
  793.     argn = 1;
  794.  
  795.     if ( argc < 2 )
  796.     pm_usage( usage );
  797.  
  798.     valign = halign = 0;
  799.     topborder = bottomborder = leftborder = rightborder = minborder = 0;
  800.  
  801.     while ( argn + 1 < argc && argv[argn][0] == '-' )
  802.     {
  803.     if (strcmp(argv[argn], "-top")  == 0)
  804.         {
  805.         if ( valign )
  806.         pm_error("only one of -top/-vcenter/-bottom may be specified",
  807.             0,0,0,0,0);
  808.         valign = TOP;
  809.         }
  810.     else if (strcmp(argv[argn], "-vcenter") == 0)
  811.         {
  812.         if ( valign )
  813.         pm_error("only one of -top/-vcenter/-bottom may be specified",
  814.             0,0,0,0,0);
  815.         valign = CENTER;
  816.         }
  817.     else if (strcmp(argv[argn], "-bottom") == 0)
  818.         {
  819.         if ( valign )
  820.         pm_error("only one of -top/-vcenter/-bottom may be specified",
  821.             0,0,0,0,0);
  822.         valign = BOTTOM; 
  823.         }
  824.     else if (strcmp(argv[argn], "-left") == 0)
  825.         {
  826.         if ( halign )
  827.         pm_error("only one of -left/-hcenter/-right may be specified",
  828.             0,0,0,0,0);
  829.         halign = LEFT;
  830.         }
  831.     else if (strcmp(argv[argn], "-hcenter") == 0)
  832.         {
  833.         if ( halign )
  834.         pm_error("only one of -left/-hcenter/-right may be specified",
  835.             0,0,0,0,0);
  836.         halign = CENTER;
  837.         }
  838.     else if (strcmp(argv[argn], "-right") == 0)
  839.         {
  840.         if ( halign )
  841.         pm_error("only one of -left/-hcenter/-right may be specified",
  842.             0,0,0,0,0);
  843.         halign = RIGHT;
  844.         }
  845.     else if (strcmp(argv[argn], "-border") == 0)
  846.         {
  847.         if ( sscanf( argv[argn+1], "%d", &minborder) != 1)
  848.         pm_usage( usage );
  849.         if ( minborder < 0)
  850.         pm_error( "border width must be greater than 0", 0,0,0,0,0 );
  851.         argn++;
  852.         }
  853.     else
  854.         pm_usage( usage );
  855.     argn++;
  856.     }
  857.  
  858.     if (argn == argc)
  859.     pm_usage( usage );
  860.  
  861.     ifd = pm_openr( argv[argn] );
  862.     argn++;
  863.  
  864.     if ( argn != argc )
  865.     {
  866.     bfd = pm_openr( argv[argn] );
  867.     argn++;
  868.     }
  869.     else
  870.     bfd = stdin;
  871.  
  872.     if ( argn != argc )
  873.     pm_usage( usage );
  874.  
  875.     ppm_pbmmaxval = 255;    /* use larger value for better results */
  876.     pixels = ppm_readppm( ifd, &cols, &rows, &maxval );
  877.  
  878.     pm_close( ifd );
  879.  
  880.     backpixels = ppm_readppm( bfd, &backcols, &backrows, &backmax );
  881.  
  882. /* Calculate the borders based on valign, halign, and minborder.  Also make
  883.  * sure that the overlayed image will fit on the background with the 
  884.  * constraints specified.
  885.  */
  886.  
  887.     switch (halign)
  888.     {
  889.     case LEFT:
  890.         leftborder = minborder;
  891.         rightborder = backcols - cols - leftborder;
  892.         break;
  893.  
  894.     case UNSPECIFIED:
  895.     case CENTER:
  896.         leftborder = (backcols - cols + 1) / 2;
  897.         rightborder = backcols - cols - leftborder;
  898.         break;
  899.  
  900.     case RIGHT:
  901.         rightborder = minborder;
  902.         leftborder = backcols - cols - rightborder;
  903.         break;
  904.     }
  905.  
  906.     if ((leftborder < minborder) || (rightborder < minborder))
  907.     pm_error( "picture is too large to overlay.  Try larger
  908. background or smaller border", 0,0,0,0,0);
  909.  
  910.     switch (valign)
  911.     {
  912.     case TOP:
  913.         topborder = minborder;
  914.         bottomborder = backrows - rows - topborder;
  915.         break;
  916.  
  917.     case UNSPECIFIED:
  918.     case CENTER:
  919.         topborder = (backrows - rows + 1) / 2;
  920.         bottomborder = backrows - rows - topborder;
  921.         break;
  922.  
  923.     case BOTTOM:
  924.         bottomborder = minborder;
  925.         topborder = backrows - rows - bottomborder;
  926.         break;
  927.     }
  928.  
  929.     if ((topborder < minborder) || (bottomborder < minborder))
  930.     pm_error( "picture is too large to overlay.  Try larger
  931. background or smaller border", 0,0,0,0,0);
  932.  
  933.  
  934.     ppm_writeppminit( stdout, backcols, backrows, maxval );
  935.     newpixelrow = ppm_allocrow( backcols );
  936.  
  937. /* For topborder, simply copy the background row to the output. */
  938.  
  939.     for ( row = 0, brow = 0; row < topborder; row++, brow++ )
  940.     {
  941.     for ( col = 0, bP = backpixels[brow], dP = newpixelrow;
  942.           col < backcols;
  943.           col++ )
  944.         *dP++ = *bP++;
  945.         
  946.     ppm_writeppmrow( stdout, newpixelrow, backcols, maxval );
  947.     }
  948.  
  949. /* For the rows that overlay, copy the left border colmuns from the background,
  950.  * followed by the overlay row, followed by the right border columns from the
  951.  * background.
  952.  */
  953.  
  954.     for ( row = 0; row < rows; row++, brow++ )
  955.     {
  956.     for ( col = 0, bP = backpixels[brow], dP = newpixelrow;
  957.           col < leftborder;
  958.           col++ )
  959.         *dP++ = *bP++;
  960.  
  961.     for ( col = 0, sP = pixels[row];
  962.           col < cols;
  963.           col++, bP++ )
  964.         *dP++ = *sP++;
  965.  
  966.     for ( col = 0; col < rightborder; col++ )
  967.         *dP++ = *bP++;
  968.  
  969.     ppm_writeppmrow( stdout, newpixelrow, backcols, maxval );
  970.     }
  971.  
  972. /* And, for the bottom border rows, simply copy from the background. */
  973.  
  974.     for ( row = 0; row < bottomborder; row++, brow++ )
  975.     {
  976.     for ( col = 0, bP = backpixels[brow], dP = newpixelrow;
  977.           col < backcols;
  978.           col++ )
  979.         *dP++ = *bP++;
  980.         
  981.     ppm_writeppmrow( stdout, newpixelrow, backcols, maxval );
  982.     }
  983.  
  984.     exit(0);
  985.     }
  986. @EOF
  987.  
  988. chmod 644 ppmoverlay.c
  989.  
  990. exit 0
  991.  
  992.